#include "JsonFlatMapAccessor.h"
#include <iostream> // For potential debug output
#include <regex>

JsonFlatMapAccessor::JsonFlatMapAccessor(nlohmann::json& json, const uint64_t& dataVersionRef, ModificationNotifier notifier)
    : m_jsonRef(json), m_dataVersionRef(dataVersionRef), m_notifier(std::move(notifier)), 
      m_cachePopulated(false), m_cachedDataVersion(0) // Initialize cached version
{}

void JsonFlatMapAccessor::populateCacheIfNeeded() {
    std::lock_guard<std::mutex> lock(m_cacheMutex); 

    // Condition to rebuild cache:
    // 1. Cache hasn't been populated yet (m_cachePopulated is false)
    // OR
    // 2. The handler's data version has changed since the cache was last built.
    if (!m_cachePopulated || m_cachedDataVersion != m_dataVersionRef) {
        // Optional Debug Output:
        // std::cout << "[Debug] Rebuilding FlatMap cache. Was Populated: " << m_cachePopulated 
        //           << ", Cached Version: " << m_cachedDataVersion 
        //           << ", Current Version: " << m_dataVersionRef << std::endl; 
        
        m_jsonStringMap.clear(); 
        exploreAndCache(m_jsonRef, "", m_jsonStringMap); 
        m_cachePopulated = true;
        m_cachedDataVersion = m_dataVersionRef; // Store the version number associated with this newly built cache
    }
}

/**
 * @brief 递归地遍历 JSON 结构，并将叶子节点以 "路径.键": "值字符串" 的形式填充到目标 Map 中。
 * 
 * 该函数是实现扁平化 JSON 的核心逻辑。它会深入到 JSON 的每一个对象和数组中，
 * 为遇到的每一个非对象、非数组的叶子节点构建一个从根节点开始的完整路径，
 * 并将该路径作为键，叶子节点值的字符串表示作为值，存入 `targetMap`。
 * 
 * @param currentJson 当前正在处理的 nlohmann::json 节点。
 * @param currentPath 从根节点到 `currentJson` 父节点的路径字符串，层级间用 '.' 分隔。
 *                    对于根节点，此参数应为空字符串 ""。
 * @param targetMap 用于存储扁平化结果的 `std::map<std::string, std::string>` 引用。
 * 
 * @note 处理逻辑：
 * 1.  **如果是 JSON 对象:**
 *     - 遍历对象的每一个键值对 (key, val)。
 *     - 根据 `currentPath` 和 `key` 构建新的路径 `newPath`。
 *       - 如果 `currentPath` 为空，`newPath` 就是 `key`。
 *       - 否则，`newPath` 是 `currentPath + "." + key`。
 *     - **如果 `val` 是对象或数组:** 递归调用 `exploreAndCache`，传入 `val`, `newPath` 和 `targetMap`，继续深入。
 *     - **如果 `val` 是叶子节点 (非 null):** 将 `newPath` 作为键，`val.dump()` (值的字符串表示) 作为值，尝试添加到 `targetMap` 中。
 *       (使用 `emplace`，如果路径已存在则不会覆盖，可以取消注释来添加重复路径警告)。
 *     - **如果 `val` 是 null:** 将 `newPath` 作为键，字符串 "null" 作为值，尝试添加到 `targetMap` 中。
 * 2.  **如果是 JSON 数组:**
 *     - **当前实现注意点:** 只递归遍历数组中的每个元素，但**不**将数组索引（如 "[0]"）添加到路径中。
 *       这意味着数组内部对象的键路径是基于数组所在对象的路径，而不是包含数组索引。
 *       例如，对于 `{"data": [{"id": 1}]}`，叶子节点的路径是 `"data.id"`。
 *     - 如果需要包含数组索引的路径（如 `"data[0].id"`），需要修改此部分的逻辑。
 * 3.  **如果是 JSON 叶子节点 (在根层级):** 函数直接返回，不会向 Map 添加任何内容。
 */
void JsonFlatMapAccessor::exploreAndCache(const nlohmann::json& currentJson, const std::string& currentPath, std::map<std::string, std::string>& targetMap) {
    if (currentJson.is_object()) {
        for (auto& [key, val] : currentJson.items()) {
            std::string newPath = currentPath.empty() ? key : currentPath + "." + key;
            if (val.is_object() || val.is_array()) {
                exploreAndCache(val, newPath, targetMap); // Recurse into objects/arrays with updated path
            } else if (!val.is_null()) { // Add non-null leaf nodes with full path as key
                // Use emplace to avoid overwriting if somehow a full path duplicates (less likely but safer)
                auto result = targetMap.emplace(newPath, val.dump());
                if (!result.second) {
                    // Optional: Warn about duplicate full paths if needed
                    // std::cerr << "Warning: Duplicate path encountered: " << newPath << std::endl;
                }
            } else {
                 auto result = targetMap.emplace(newPath, "null"); // Explicitly store null as "null"
                  if (!result.second) {
                    // Optional: Warn about duplicate full paths if needed
                    // std::cerr << "Warning: Duplicate path encountered: " << newPath << std::endl;
                }
            }
        }
    } else if (currentJson.is_array()) {
        // Current logic only adds keys from objects. If array elements need paths (e.g., "arr[0].key"), 
        // this part needs modification to iterate with index and construct paths accordingly.
        // For now, keep original behavior: recurse into elements, path doesn't include array index.
        for (const auto& element : currentJson) {
            exploreAndCache(element, currentPath, targetMap); // Path doesn't change for elements within an array in this scheme
        }
    }
     // If it's a primitive type at the root, the loop won't run, map remains empty (or as is)
}

std::string JsonFlatMapAccessor::getValue(const std::string& key) {
    populateCacheIfNeeded(); // Ensure the cache is populated
    std::lock_guard<std::mutex> lock(m_cacheMutex); // Lock for reading the cache
    // Now expects 'key' to be the full path
    auto it = m_jsonStringMap.find(key);
    if (it != m_jsonStringMap.end()) {
        return it->second;
    }
    return ""; // Return empty string if key not found in cache
}

std::vector<std::string> JsonFlatMapAccessor::getKeys() {
    populateCacheIfNeeded(); // Ensure the cache is up-to-date
    std::lock_guard<std::mutex> lock(m_cacheMutex); // Lock for reading the cache

    std::vector<std::string> keys;
    keys.reserve(m_jsonStringMap.size()); // Reserve space for efficiency
    for (const auto& pair : m_jsonStringMap) {
        keys.push_back(pair.first);
    }
    return keys;
}

std::vector<std::string> JsonFlatMapAccessor::findKeysByRegex(const std::string& regexPattern) {
    populateCacheIfNeeded(); // Ensure the cache is up-to-date
    std::lock_guard<std::mutex> lock(m_cacheMutex); // Lock for reading the cache

    std::vector<std::string> matchingKeys;
    try {
        // Use ECMAScript syntax, which is common and powerful
        std::regex pattern(regexPattern, std::regex_constants::ECMAScript);

        for (const auto& pair : m_jsonStringMap) {
            if (std::regex_match(pair.first, pattern)) {
                matchingKeys.push_back(pair.first);
            }
        }
    } catch (const std::regex_error& e) {
        // Handle invalid regex patterns gracefully
        std::cerr << "JsonFlatMapAccessor::findKeysByRegex Error: Invalid regex pattern \"" 
                  << regexPattern << "\". " << e.what() << std::endl;
        // Return empty vector on error
        matchingKeys.clear(); 
    }
    return matchingKeys;
} 